package sweet.mvc

import javax.servlet.http._
import org.slf4j.{ Logger, LoggerFactory }
import scala.collection.mutable.HashMap

case class View(name: String, models: (String, AnyRef)*)
case class PathView(m: (String, AnyRef)*) extends View("to-be-filled-later", m : _*)
case object EmptyView extends View(null)

trait Controller{  
  type Request = HttpServletRequest
  type Response = HttpServletResponse
  type Handler = (Request, Response) => View
  
  //factory to create a simple handler that has only view name without any models.
  object ViewHandler{
    def apply(name: String) = (req: Request, resp: Response) => View(name)
  }

  def handlers: HashMap[String, Handler]
    
  def handle(url: String)(handler: =>View){ 
    handlers(url) = (req: Request, resp: Response) => handler 
  }
  def handleR(url: String)(handler: (Request)=>View){ 
    handlers(url) = (req: Request, resp: Response) => handler(req) 
  }
  def handleRP(url: String)(handler: (Request, Response)=>View){ 
    handlers(url) = (req: Request, resp: Response) => handler(req, resp) 
  }
  
  def process(req: Request, resp: Response): View 
}

abstract class AbstractController extends Controller{
  val logger = LoggerFactory.getLogger(getClass)
  val defaultHandlerView = "/index"   
  val handlers: HashMap[String, Handler] = {
    val map = new HashMap[String, Handler]
    map(defaultHandlerView) = ViewHandler(defaultHandlerView) //default value
    map
  }
  
  def process(req: Request, resp: Response): View = {
    //HANDLER_PATH_KEY should already been saved by dispatcher.
    val handlerPath = req.getAttribute(Constants.HANDLER_PATH_KEY).asInstanceOf[String]
    val handler = 
      if(handlerPath == "" || handlerPath == "/"){ 
        logger.debug("Handler not specified on url. using default " + defaultHandlerView)
        handlers(defaultHandlerView)
      }else{ 
        logger.debug("Finding handler for " + handlerPath)
        findHandler(handlerPath, req)
      }
    logger.debug("Invoking handler")
    val view = handler(req, resp)
    
    if(view.isInstanceOf[PathView]) View(handlerPath, view.models: _*)
    else view
  }
  
  def findHandler(handlerPath: String, req: Request) = handlers(handlerPath)
}

class UrlViewController extends AbstractController {   
  override def findHandler(handlerPath: String, req: Request): Handler = {
    logger.debug("Returning a handler with view matching to url path " + handlerPath)
    ViewHandler(handlerPath)
  }  
}
